// WaveCameraStream.cpp: implementation of the CWaveCameraStream class.
//
//////////////////////////////////////////////////////////////////////

#pragma warning(disable:4786)

#include "stdafx.h"
#include "RMSTranslator.h"
#include "../RMSServer/RMSBaseServer.h"
#include "Camera.h"
#include "../Common/RMSLog.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define	PACKET_SIZE 42*100 //42 // 4 + 1 + 4 + 33 

CWaveCameraStream::CWaveCameraStream(CBaseServer *p)
{
	pBaseServer=p;
	m_bActive = FALSE;
	m_pOwner = 0;
	
	m_pData = new BYTE[PACKET_SIZE];
}

CWaveCameraStream::~CWaveCameraStream()
{
	m_pOwner=0;
	if(m_bActive)
	{
		Terminate(TRUE);
	}

	if(m_pData) delete[] m_pData;
	m_pData=0;
}

DWORD CWaveCameraStream::OnTerminate()
{
	if(m_udpSocket)
	{
		shutdown(m_udpSocket, SD_BOTH);
		closesocket(m_udpSocket);
		m_udpSocket = 0;
	}
	return DEFAULT_TERMINATION_TIMEOUT;
}

BOOL CWaveCameraStream::Execute()
{
	return CRMSThread::Execute();
}

DWORD CWaveCameraStream::ThreadFunc()
{
	TRACE1("%x - CWaveCameraStream::ThreadFunc() - started\n", this);
	int		nLen, nPort, i;
	int		ID;
	bool	binded;
	DWORD	dwTag;
	BYTE*	pDst;
	LINGER  linger = { 1,0 };
	int	sin_port=htons(pBaseServer->BasePort);
	BOOL bReuse=TRUE;// reset port/address
	if (m_pOwner==0) goto exit;

	Write2Log2("CWaveCameraStreamID=",m_pOwner->GetID());
	m_udpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
	if(m_udpSocket == INVALID_SOCKET)
	{
		TRACE0("Unable to create udp socket\n");
		Write2Log1("Audio cam Unable to bind socket","");
		goto exit;
	}
	//Fixes Bug in MFC Socket Impl
	setsockopt(m_udpSocket,SOL_SOCKET,SO_LINGER,(LPCTSTR)&linger,sizeof(linger));
//	setsockopt(m_udpSocket, SOL_SOCKET, SO_REUSEADDR,(LPCTSTR)&bReuse,sizeof(BOOL));

	binded = false;
	memset (&m_saServer, 0, sizeof(SOCKADDR_IN)); 
	m_saServer.sin_family = PF_INET;
	//m_saServer.sin_port = htons(10000)+100;// local port
	//m_saServer.sin_addr.s_addr = INADDR_ANY;
	m_saServer.sin_port = htons(ntohs(sin_port)+200);// +200;

	if (m_pOwner==0) goto exit;
	m_saServer.sin_addr.s_addr = inet_addr(m_pOwner->GetIP());
	// find and bin local port to bind to
	for (i=0;i<100;i++) 
	{
		if (m_pOwner==0) goto exit;
		if (m_bQuit)
		{
				goto exit;
		}
		if(bind(m_udpSocket,(sockaddr*)&m_saServer,sizeof(SOCKADDR_IN)) != INVALID_SOCKET)
		{
			binded = true;
			break;
		}
		else
		{
			m_saServer.sin_port=htons(ntohs(m_saServer.sin_port)+1);
		}
	}
	if(!binded)
	{
		goto exit;
	}
	Write2Log2("Audio cam: m_saServer.sin_port =",ntohs(m_saServer.sin_port));
	Write2Log1("Aideo cam: m_saServer.sin_addr.s_addr=",inet_ntoa(m_saServer.sin_addr));

	// Send udp port 
	if (m_pOwner==0) goto exit;
	dwTag = TAG_SOUNDUDPPORT;
	nPort = ntohs(m_saServer.sin_port);
	nLen = sizeof(DWORD) + sizeof(int);
	
	pDst = m_pData;
	memcpy(pDst, &dwTag, sizeof(DWORD)); pDst += sizeof(DWORD);
	memcpy(pDst, &nPort, sizeof(int));
	if(sendto(m_udpSocket, (char*)m_pData, nLen, 0, (LPSOCKADDR)&m_saCamera, sizeof(SOCKADDR_IN)) == INVALID_SOCKET)
	{
		goto exit;
	}
	
	while(!m_bQuit)
	{
		if (m_pOwner==0) goto exit;
		nLen = sizeof(SOCKADDR_IN);
		/*
		if (m_pOwner) {
			if (m_pOwner->lastReceivedAudioTime==0) 
			m_pOwner->lastReceivedAudioTime=timeGetTime();// update time
		}
		*/
		if(recvfrom(m_udpSocket, (char*)m_pData, PACKET_SIZE, 0, (LPSOCKADDR)&m_saCamera, &nLen) == SOCKET_ERROR)
		{
			TRACE0("Unable to recive audio data from server\n");
			break;
		}
		if (m_pOwner) m_pOwner->lastReceivedAudioTime=timeGetTime();// update time

		dwTag = *((DWORD*)m_pData);
		if(dwTag != TAG_RMSSOUND_v01)
		{
			TRACE0("This format of audio is not supported\n");
			goto exit;
		}
		
		ID = m_pOwner->GetID();
				
		EnterCriticalSection(pBaseServer->GetDataPtr_CriticalAudio(ID));
		*pBaseServer->GetDataPtr_SizeAudio(ID) = *((DWORD*)(m_pData+5));
		memcpy(pBaseServer->GetDataPtr_dtAudio(ID),m_pData+9,*((DWORD*)(m_pData+5)));
		LeaveCriticalSection(pBaseServer->GetDataPtr_CriticalAudio(ID));

		if (pBaseServer)
		{
			pBaseServer->SendWaveEvent(ID);
		}
//		Sleep(0);
	}	
exit:
	if (m_udpSocket) {
		shutdown(m_udpSocket,SD_BOTH);
		closesocket(m_udpSocket);
		m_udpSocket=0;
	}
	TRACE1("%x - CWaveCameraStream::ThreadFunc() - finished\n", this);
	return 0;
}

BOOL CWaveCameraStream::Init(SOCKADDR_IN saWave, LPCLiveCamera pOwner)
{
	m_saCamera = saWave;
	m_pOwner = pOwner;
	
	Execute();
	m_bActive = TRUE;
	return TRUE;
}

BOOL CWaveCameraStream::Stop()
{
	m_bActive = FALSE;
	Terminate();

	return TRUE;
}

BOOL CWaveCameraStream::Restart()
{
	Execute();
	m_bActive = TRUE;
	return TRUE;
}

BOOL CWaveCameraStream::IsActive() const
{
	return m_bActive;
}

BOOL CWaveCameraStream::CloseProcess()
{
	Terminate(1);
	return TRUE;
}

